package top.zhangjianyong.tools.indicator.score;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicators;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 技术指标综合打分服务
 * 基于各技术指标计算结果进行综合评分
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Slf4j
@Service
public class IndicatorScoreService {

    /**
     * 计算技术指标综合得分
     *
     * @param indicators 所有技术指标计算结果
     * @param dataList   K线数据列表
     * @return 综合打分结果
     */
    public IndicatorScoreResult calculateScore(TechnicalIndicators indicators, List<ETFData> dataList) {
        if (indicators == null || dataList == null || dataList.isEmpty()) {
            log.warn("指标数据或K线数据为空，无法计算综合得分");
            return null;
        }

        IndicatorScoreResult result = new IndicatorScoreResult();

        // 计算各指标得分
        int macdVote = calculateMACDScore(indicators);
        result.setMacdScore(BigDecimal.valueOf(macdVote));
        result.addVote("MACD", macdVote);

        int kdjVote = calculateKDJScore(indicators);
        result.setKdjScore(BigDecimal.valueOf(kdjVote));
        result.addVote("KDJ", kdjVote);

        int bollVote = calculateBollScore(indicators, dataList);
        result.setBollScore(BigDecimal.valueOf(bollVote));
        result.addVote("BOLL", bollVote);

        int rsiVote = calculateRSIScore(indicators);
        result.setRsiScore(BigDecimal.valueOf(rsiVote));
        result.addVote("RSI", rsiVote);

        int maVote = calculateMovingAverageScore(indicators, dataList);
        result.setMovingAverageScore(BigDecimal.valueOf(maVote));
        result.addVote("MA", maVote);

        int volumeVote = calculateVolumeScore(indicators, dataList);
        result.setVolumeScore(BigDecimal.valueOf(volumeVote));
        result.addVote("VOLUME", volumeVote);

        int otherVote = calculateOtherScore(indicators, dataList);
        result.setOtherScore(BigDecimal.valueOf(otherVote));
        result.addVote("OTHER", otherVote);

        // 计算综合得分
        BigDecimal totalScore = calculateTotalScore(result);
        result.determineSignal(totalScore);

        return result;
    }

    /**
     * MACD投票：金叉且柱状为正 -> 1；死叉且柱状为负 -> -1；其余0
     */
    private int calculateMACDScore(TechnicalIndicators indicators) {
        TechnicalIndicatorResult macdResult = indicators.getResult("MACD");
        if (macdResult == null || !macdResult.isSuccess()) {
            return 0;
        }

        BigDecimal dif = macdResult.getBigDecimalValue("macd_dif");
        BigDecimal dea = macdResult.getBigDecimalValue("macd_dea");
        BigDecimal macd = macdResult.getBigDecimalValue("macd");

        if (dif == null || dea == null || macd == null) {
            return 0;
        }

        // 判断DIF与DEA的差异
        BigDecimal diff = dif.subtract(dea).abs();
        BigDecimal threshold = new BigDecimal("0.001");

        // DIF与DEA接近
        if (diff.compareTo(threshold) < 0) {
            return 0;
        }

        // 判断金叉/死叉状态（基于当前DIF和DEA的关系）
        int difDeaCompare = dif.compareTo(dea);
        int macdCompare = macd.compareTo(BigDecimal.ZERO);

        if (difDeaCompare > 0 && macdCompare > 0) {
            return 1;
        } else if (difDeaCompare < 0 && macdCompare < 0) {
            return -1;
        }
        return 0;
    }

    /**
     * KDJ投票：J<20 或 K>D 且未超买 -> 1；J>80 或 K<D 且未超卖 -> -1；其余0
     */
    private int calculateKDJScore(TechnicalIndicators indicators) {
        TechnicalIndicatorResult kdjResult = indicators.getResult("KDJ");
        if (kdjResult == null || !kdjResult.isSuccess()) {
            return 0;
        }

        BigDecimal k = kdjResult.getBigDecimalValue("kdj_k");
        BigDecimal d = kdjResult.getBigDecimalValue("kdj_d");
        BigDecimal j = kdjResult.getBigDecimalValue("kdj_j");

        if (k == null || d == null || j == null) {
            return 0;
        }

        if (j.compareTo(new BigDecimal("80")) > 0 || (k.compareTo(d) < 0 && j.compareTo(new BigDecimal("20")) > 0)) {
            return -1;
        }
        if (j.compareTo(new BigDecimal("20")) < 0 || (k.compareTo(d) > 0 && j.compareTo(new BigDecimal("80")) < 0)) {
            return 1;
        }
        return 0;
    }

    /**
     * 计算布林带指标得分
     * 评分规则：
     * - 价格突破上轨（价格>上轨）：-1分
     * - 价格突破下轨（价格<下轨）：+1分
     * - 价格在中轨上方（价格>中轨）：+0.5分
     * - 价格在中轨下方（价格<中轨）：-0.5分
     * - 价格在中轨附近（|价格-中轨|/中轨 < 0.01）：0分
     *
     * @param indicators 技术指标结果
     * @param dataList   K线数据列表
     * @return 布林带得分
     */
    private int calculateBollScore(TechnicalIndicators indicators, List<ETFData> dataList) {
        TechnicalIndicatorResult bollResult = indicators.getResult("BOLL");
        if (bollResult == null || !bollResult.isSuccess() || dataList.isEmpty()) {
            return 0;
        }

        BigDecimal upper = bollResult.getBigDecimalValue("boll_upper");
        BigDecimal middle = bollResult.getBigDecimalValue("boll_middle");
        BigDecimal lower = bollResult.getBigDecimalValue("boll_lower");
        BigDecimal currentPrice = dataList.get(dataList.size() - 1).getValue();

        if (upper == null || middle == null || lower == null || currentPrice == null) {
            return 0;
        }

        if (currentPrice.compareTo(upper) > 0) {
            return -1;
        } else if (currentPrice.compareTo(lower) < 0) {
            return 1;
        }
        BigDecimal diff = currentPrice.subtract(middle).abs();
        BigDecimal ratio = diff.divide(middle, 4, RoundingMode.HALF_UP);
        if (ratio.compareTo(new BigDecimal("0.01")) < 0) {
            return 0;
        }
        if (currentPrice.compareTo(middle) > 0) {
            return 1;
        } else if (currentPrice.compareTo(middle) < 0) {
            return -1;
        }
        return 0;
    }

    /**
     * 计算RSI指标得分
     * 评分规则：
     * - RSI < 30（超卖）：+1分
     * - RSI > 70（超买）：-1分
     * - 30 ≤ RSI ≤ 70（正常区间）：0分
     *
     * @param indicators 技术指标结果
     * @return RSI得分
     */
    private int calculateRSIScore(TechnicalIndicators indicators) {
        TechnicalIndicatorResult rsiResult = indicators.getResult("RSI");
        if (rsiResult == null || !rsiResult.isSuccess()) {
            return 0;
        }

        BigDecimal rsi = rsiResult.getBigDecimalValue("rsi");
        if (rsi == null) {
            return 0;
        }

        // RSI < 30（超卖）：+1分
        if (rsi.compareTo(new BigDecimal("30")) < 0) {
            return 1;
        }
        // RSI > 70（超买）：-1分
        else if (rsi.compareTo(new BigDecimal("70")) > 0) {
            return -1;
        }
        // 30 ≤ RSI ≤ 70（正常区间）：0分
        else {
            return 0;
        }
    }

    /**
     * 均线投票：价格与均线多头均满足 -> 1；空头满足 -> -1；否则0
     */
    private int calculateMovingAverageScore(TechnicalIndicators indicators, List<ETFData> dataList) {
        TechnicalIndicatorResult smaResult = indicators.getResult("SMA");
        if (smaResult == null || !smaResult.isSuccess() || dataList.isEmpty()) {
            return 0;
        }

        BigDecimal sma5 = smaResult.getBigDecimalValue("sma_5");
        BigDecimal sma10 = smaResult.getBigDecimalValue("sma_10");
        BigDecimal sma20 = smaResult.getBigDecimalValue("sma_20");
        BigDecimal sma60 = smaResult.getBigDecimalValue("sma_60");
        BigDecimal currentPrice = dataList.get(dataList.size() - 1).getValue();

        if (currentPrice == null) {
            return 0;
        }

        boolean bullishPrice = sma20 != null && sma60 != null
            && currentPrice.compareTo(sma20) > 0
            && currentPrice.compareTo(sma60) > 0;
        boolean bearishPrice = sma20 != null && sma60 != null
            && currentPrice.compareTo(sma20) < 0
            && currentPrice.compareTo(sma60) < 0;

        boolean bullishOrder = sma5 != null && sma10 != null && sma20 != null && sma60 != null
            && sma5.compareTo(sma10) > 0
            && sma10.compareTo(sma20) > 0
            && sma20.compareTo(sma60) > 0;
        boolean bearishOrder = sma5 != null && sma10 != null && sma20 != null && sma60 != null
            && sma5.compareTo(sma10) < 0
            && sma10.compareTo(sma20) < 0
            && sma20.compareTo(sma60) < 0;

        if (bullishPrice && bullishOrder) {
            return 1;
        } else if (bearishPrice && bearishOrder) {
            return -1;
        }

        return 0;
    }

    /**
     * 计算成交量指标得分
     * 评分规则：
     * - 成交量放大配合上涨（vol_ratio ≥ 1.2且价格上涨）：+1分
     * - 成交量放大配合下跌（vol_ratio ≥ 1.2且价格下跌）：-1分
     * - 成交量萎缩（vol_ratio ≤ 0.8）：-0.5分
     * - 成交量正常（0.8 < vol_ratio < 1.2）：0分
     *
     * @param indicators 技术指标结果
     * @param dataList   K线数据列表
     * @return 成交量得分
     */
    private int calculateVolumeScore(TechnicalIndicators indicators, List<ETFData> dataList) {
        TechnicalIndicatorResult volumeResult = indicators.getResult("VOLUME");
        if (volumeResult == null || !volumeResult.isSuccess() || dataList.size() < 2) {
            return 0;
        }

        BigDecimal volRatio = volumeResult.getBigDecimalValue("vol_ratio");
        if (volRatio == null) {
            return 0;
        }

        // 判断价格变化
        ETFData currentData = dataList.get(dataList.size() - 1);
        ETFData previousData = dataList.get(dataList.size() - 2);
        BigDecimal currentPrice = currentData.getValue();
        BigDecimal previousPrice = previousData.getValue();

        if (currentPrice == null || previousPrice == null) {
            return 0;
        }

        boolean priceRising = currentPrice.compareTo(previousPrice) > 0;

        // 成交量放大配合上涨（vol_ratio ≥ 1.2且价格上涨）：+1分
        if (volRatio.compareTo(new BigDecimal("1.2")) >= 0 && priceRising) {
            return 1;
        }
        // 成交量放大配合下跌（vol_ratio ≥ 1.2且价格下跌）：-1分
        else if (volRatio.compareTo(new BigDecimal("1.2")) >= 0 && !priceRising) {
            return -1;
        }

        return 0;
    }

    /**
     * 计算其他技术指标得分（ADX和OBV）
     * 评分规则：
     * - ADX > 25且趋势向上：+0.5分
     * - ADX > 25且趋势向下：-0.5分
     * - OBV与价格同向：+0.5分
     * - OBV与价格背离：-0.5分
     *
     * @param indicators 技术指标结果
     * @param dataList   K线数据列表
     * @return 其他指标得分
     */
    private int calculateOtherScore(TechnicalIndicators indicators, List<ETFData> dataList) {
        boolean bullish = false;
        boolean bearish = false;

        // ADX评分
        TechnicalIndicatorResult adxResult = indicators.getResult("ADX");
        if (adxResult != null && adxResult.isSuccess()) {
            BigDecimal adx = adxResult.getBigDecimalValue("adx");
            BigDecimal plusDi = adxResult.getBigDecimalValue("plus_di");
            BigDecimal minusDi = adxResult.getBigDecimalValue("minus_di");

            if (adx != null && adx.compareTo(new BigDecimal("25")) > 0) {
                // 判断趋势方向：+DI > -DI 表示趋势向上
                if (plusDi != null && minusDi != null && plusDi.compareTo(minusDi) > 0) {
                    bullish = true;
                } else if (plusDi != null && minusDi != null && plusDi.compareTo(minusDi) < 0) {
                    bearish = true;
                }
            }
        }

        // OBV评分
        TechnicalIndicatorResult obvResult = indicators.getResult("OBV");
        if (obvResult != null && obvResult.isSuccess() && dataList.size() >= 2) {
            BigDecimal obvChangeRate = obvResult.getBigDecimalValue("obv_change_rate");
            ETFData currentData = dataList.get(dataList.size() - 1);
            ETFData previousData = dataList.get(dataList.size() - 2);
            BigDecimal currentPrice = currentData.getValue();
            BigDecimal previousPrice = previousData.getValue();

            if (obvChangeRate != null && currentPrice != null && previousPrice != null) {
                BigDecimal priceChangeRate = currentPrice.subtract(previousPrice)
                    .divide(previousPrice, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"));

                // OBV与价格同向：+0.5分
                if ((obvChangeRate.compareTo(BigDecimal.ZERO) > 0 && priceChangeRate.compareTo(BigDecimal.ZERO) > 0)
                    || (obvChangeRate.compareTo(BigDecimal.ZERO) < 0 && priceChangeRate.compareTo(BigDecimal.ZERO) < 0)) {
                    bullish = true;
                }
                // OBV与价格背离：-0.5分
                else if ((obvChangeRate.compareTo(BigDecimal.ZERO) > 0 && priceChangeRate.compareTo(BigDecimal.ZERO) < 0)
                    || (obvChangeRate.compareTo(BigDecimal.ZERO) < 0 && priceChangeRate.compareTo(BigDecimal.ZERO) > 0)) {
                    bearish = true;
                }
            }
        }

        if (bullish && !bearish) {
            return 1;
        } else if (bearish && !bullish) {
            return -1;
        }
        return 0;
    }

    private BigDecimal calculateTotalScore(IndicatorScoreResult result) {
        int total = 0;
        if (result.getMacdScore() != null) {
            total += result.getMacdScore().intValue();
        }
        if (result.getKdjScore() != null) {
            total += result.getKdjScore().intValue();
        }
        if (result.getBollScore() != null) {
            total += result.getBollScore().intValue();
        }
        if (result.getRsiScore() != null) {
            total += result.getRsiScore().intValue();
        }
        if (result.getMovingAverageScore() != null) {
            total += result.getMovingAverageScore().intValue();
        }
        if (result.getVolumeScore() != null) {
            total += result.getVolumeScore().intValue();
        }
        if (result.getOtherScore() != null) {
            total += result.getOtherScore().intValue();
        }
        return new BigDecimal(total);
    }
}

